#include <generated/csr.h>
#ifdef CSR_OLED_BASE
#include "oled.h"

unsigned char oled_buffer[128*32/8] = {
	/* LiteX logo */
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x80, 0x60, 0x00, 0x50, 0xA0,
	0x00, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0xC0, 0xC0, 0xE0, 0xE0, 0xF0, 0xF8, 0xF8, 0xFC, 0xF8,
	0xF8, 0xF0, 0xF0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x05, 0x02,
	0x05, 0x0A, 0x04, 0x09, 0x36, 0x00, 0x6C, 0x10, 0x20, 0x98, 0xC0, 0xC0, 0xE0, 0xF0, 0xF0, 0xF8,
	0xFC, 0xFC, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x3F, 0x1F, 0x1F, 0x0F, 0x0F, 0x07, 0x03,
	0x23, 0x21, 0x71, 0x30, 0x70, 0x30, 0x70, 0x30, 0x70, 0x30, 0x70, 0x30, 0x70, 0x30, 0xF0, 0xF0,
	0xF0, 0xF0, 0xE0, 0x60, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xE0, 0xE0,
	0xF0, 0xF0, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xE0, 0xE0, 0xF0,
	0x70, 0x30, 0x10, 0x00, 0x60, 0x20, 0x70, 0x30, 0x30, 0x70, 0x30, 0x70, 0x30, 0x70, 0x30, 0x70,
	0x30, 0x70, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0x30, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0xC0, 0xC0, 0xE0,
	0xE0, 0xF0, 0xF8, 0xF8, 0xFC, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x3F, 0x1F, 0x1F,
	0x0F, 0x07, 0x07, 0x33, 0x09, 0x31, 0x48, 0x94, 0x28, 0x40, 0xB0, 0x30, 0x78, 0xB2, 0x3B, 0xB3,
	0x3B, 0x1B, 0x33, 0x3B, 0x1B, 0x33, 0x1B, 0x3B, 0x13, 0x3B, 0x1B, 0x3F, 0x3F, 0x1F, 0x1F, 0x0F,
	0x03, 0x11, 0x38, 0x18, 0x38, 0x10, 0x38, 0x18, 0x38, 0x18, 0x3C, 0x1E, 0x3F, 0x1F, 0x3F, 0x1B,
	0x39, 0x10, 0x38, 0x18, 0x18, 0x00, 0x00, 0x10, 0x38, 0x1C, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x18, 0x3C,
	0x3E, 0x1F, 0x0F, 0x07, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x07, 0x0F, 0x0F, 0x1F, 0x3F, 0x3F, 0x3F,
	0x1F, 0x1F, 0x0F, 0x0F, 0x07, 0x07, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, 0x05, 0x0A, 0x10, 0x0A,
	0x05, 0x08, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

static void busy_wait(unsigned int ds)
{
	timer0_en_write(0);
	timer0_reload_write(0);
	timer0_load_write(CONFIG_CLOCK_FREQUENCY/100*ds);
	timer0_en_write(1);
	timer0_update_value_write(1);
	while(timer0_value_read()) timer0_update_value_write(1);
}

void oled_spi_write(unsigned char value) {
	oled_spi_mosi_write(value);
	oled_spi_length_write(8);
	oled_spi_ctrl_write(1);
	while(oled_spi_status_read() == 0);
}

void oled_write_command(unsigned char value) {
	oled_gpio_out_write(OLED_RESET);
	oled_spi_write(value);
}

void oled_write_data(unsigned char value) {
	oled_gpio_out_write(OLED_RESET | OLED_DC);
	oled_spi_write(value);
}

void oled_init(void) {
	oled_gpio_out_write(OLED_RESET | OLED_VBAT);
	busy_wait(1); /* 1ms delay */
	oled_gpio_out_write(OLED_VBAT);
	busy_wait(10); /* 10ms delay */
	oled_gpio_out_write(OLED_RESET | OLED_VBAT);

	/* 128x32 oled init sequence */
	oled_write_command(SSD1306_DISPLAYOFF);
	oled_write_command(SSD1306_SETDISPLAYCLOCKDIV);
	oled_write_command(0x80);
	oled_write_command(SSD1306_SETMULTIPLEX);
	oled_write_command(0x1f);
	oled_write_command(SSD1306_SETDISPLAYOFFSET);
	oled_write_command(0x00);
	oled_write_command(SSD1306_SETSTARTLINE | 0x0);
	oled_write_command(SSD1306_CHARGEPUMP);
	oled_write_command(0x14);
	oled_write_command(SSD1306_MEMORYMODE);
	oled_write_command(0x00);
	oled_write_command(SSD1306_SEGREMAP | 0x1);
	oled_write_command(SSD1306_COMSCANDEC);
	oled_write_command(SSD1306_SETCOMPINS);
	oled_write_command(0x02);
	oled_write_command(SSD1306_SETCONTRAST);
	oled_write_command(0x8f);
	oled_write_command(SSD1306_SETPRECHARGE);
	oled_write_command(0xf1);
	oled_write_command(SSD1306_SETVCOMDETECT);
	oled_write_command(0x40);
	oled_write_command(SSD1306_DISPLAYALLON_RESUME);
	oled_write_command(SSD1306_NORMALDISPLAY);

    oled_gpio_out_write(OLED_RESET);

	oled_write_command(SSD1306_DISPLAYON);
}

void oled_refresh(void) {
	int i;

	oled_write_command(SSD1306_COLUMNADDR);
	oled_write_command(0);
	oled_write_command(127);

	oled_write_command(SSD1306_PAGEADDR);
	oled_write_command(0);
	oled_write_command(3);

	for(i=0; i<128*32/8; i++) {
		oled_write_data(oled_buffer[i]);
	}
}

#endif